//! Kernel heap management in Zig
//! SPDX-License-Identifier: MPL-2.0

const std = @import("std");
const lib = @import("lib.zig");
const frame = @import("frame.zig");

const MemoryError = lib.MemoryError;
const PAGE_SIZE = lib.PAGE_SIZE;

// Heap slot information
pub const SlotInfo = struct {
    size: usize,
    alignment: usize,
    slot_type: SlotType,

    pub const SlotType = enum {
        Small,   // < 256 bytes
        Medium,  // 256 bytes - 2KB
        Large,   // 2KB - 64KB
        Huge,    // > 64KB
    };

    pub fn fromLayout(layout: std.mem.Allocator.Layout) SlotInfo {
        const size = layout.len;
        const alignment = layout.alignment;
        
        const slot_type = if (size < 256) SlotType.Small
        else if (size < 2048) SlotType.Medium
        else if (size < 65536) SlotType.Large
        else SlotType.Huge;

        return SlotInfo{
            .size = std.mem.alignForward(usize, size, alignment),
            .alignment = alignment,
            .slot_type = slot_type,
        };
    }
};

// Heap slot representing an allocated memory region
pub const HeapSlot = struct {
    ptr: [*]u8,
    size: usize,
    alignment: usize,

    const Self = @This();

    pub fn init(ptr: [*]u8, size: usize, alignment: usize) Self {
        return Self{
            .ptr = ptr,
            .size = size,
            .alignment = alignment,
        };
    }

    pub fn asSlice(self: Self) []u8 {
        return self.ptr[0..self.size];
    }

    pub fn asMutSlice(self: Self) []u8 {
        return self.ptr[0..self.size];
    }

    pub fn addr(self: Self) usize {
        return @intFromPtr(self.ptr);
    }

    pub fn zero(self: Self) void {
        @memset(self.asSlice(), 0);
    }
};

// Global heap allocator interface
pub const GlobalHeapAllocator = struct {
    allocFn: *const fn (self: *anyopaque, layout: std.mem.Allocator.Layout) ?HeapSlot,
    deallocFn: *const fn (self: *anyopaque, slot: HeapSlot) void,
    ptr: *anyopaque,

    const Self = @This();

    pub fn alloc(self: Self, layout: std.mem.Allocator.Layout) ?HeapSlot {
        return self.allocFn(self.ptr, layout);
    }

    pub fn dealloc(self: Self, slot: HeapSlot) void {
        self.deallocFn(self.ptr, slot);
    }
};

// Tests
test "slot info creation" {
    const testing = std.testing;
    const layout = std.mem.Allocator.Layout{ .len = 100, .alignment = 8 };
    const slot_info = SlotInfo.fromLayout(layout);
    
    try testing.expectEqual(SlotInfo.SlotType.Small, slot_info.slot_type);
    try testing.expectEqual(@as(usize, 8), slot_info.alignment);
}